'abuschedule.monkey by Belimoth

'TODO
'	interpolation and easing functions
'	Pause() and Resume()
'	test file for Timer stuff
'	GetTween/TimerStatus() method or similar
'	merge into abuschedulecomponent?

Strict
Import reflection
Import skn3.tween
Import abutime



Interface ISchedule
	Method AddTween:Void(name:String, value:Float, duration:Int, equation:TweenEquationCall = Tween.Linear)
	Method PauseTween:Void(name:String)
	Method ResumeTween:Void(name:String)
	Method RemoveTween:Void(name:String)
	Method ClearTweens:Void()
	Method OnTweenComplete:Void(name:String)
End



Class AbuTween Implements IJuggleable

Private
	'Global ARGUMENT:ClassInfo[] = [ FloatClass() ]
	Field _active:Bool = True
	
Public
	Global juggler := New Juggler<AbuTween>
	
	Method New(targetObject:Object, name:String, value:Float, duration:Int, equation:TweenEquationCall = Tween.Linear)
		Self._targetObject = targetObject
		Local classInfo := GetClass(targetObject)
		If classInfo = Null Then Error("Reflected class not found.")
		'Print classInfo.Name
		
		Self._targetGetProperty = classInfo.GetMethod(name, [], True)
		If _targetGetProperty = Null
			_targetField = classInfo.GetField(name)
			If _targetField = Null
				Error("Reflected get method '" + name +"' not found.")
			Else
				_isField = True
				If _targetField.Type = IntClass() Then _intProperty = True
			EndIf
		Else
			If _targetGetProperty.ReturnType = IntClass() Then _intProperty = True
		EndIf
		
		If Not _isField
			If _intProperty
				Self._targetSetProperty = classInfo.GetMethod(name, [ IntClass() ], True)
			Else
				Self._targetSetProperty = classInfo.GetMethod(name, [ FloatClass() ], True)
			Endif
			If _targetSetProperty = Null Then Error("Reflected set method '" + name +"' not found.")
		EndIf
		
		Self._valueCurrentBoxed = New Object[1]
		_GetValue()
		
		If _intProperty
			Self._valueStart = IntObject(_valueCurrentBoxed[0]).value
		Else
			Self._valueStart = FloatObject(_valueCurrentBoxed[0]).value
		End
		
		Self._valueEnd = value
		Self._valueDelta = value - _valueStart
		Self._timeStart = CurrentTime()
		Self._duration = duration
		Self._timeEnd = _timeStart + duration
		
		Self._equation = equation
		
		juggler.Add(Self)
	End
	
	Method Destroy:Void()
		juggler.Remove(Self)		'TODO this doesn't remove the tween from the tweener
	End
	
	Method Active:Bool() Property
		Return _active
	End	
	
	Method Juggle:Void(timePassed:Int)
		Self._timePassed += timePassed
		'_completion = Float(_timePassed) / Float(_duration)

		Update()
		
		If _intProperty
			IntObject(_valueCurrentBoxed[0]).value = _valueCurrent
		Else
			FloatObject(_valueCurrentBoxed[0]).value = _valueCurrent
		Endif
		_SetValue()
		
		If _timePassed > _duration '_completion >= 1
			OnComplete()
		Endif
	End
	
	Method Update:Void()
		If _timePassed > _duration '_completion >= 1
			_valueCurrent = _valueEnd
		Else
			_valueCurrent = _equation.Call(_timePassed, _valueStart, _valueDelta, _duration)
		Endif
	End
	
	Method OnComplete:Void()
		Destroy()
	End
	
	Method Pause:Void()
		'TODO
	End
	
	Method Resume:Void()
		'TODO
	End
	
Private
	Field _targetObject:Object
	Field _targetGetProperty:MethodInfo
	Field _targetSetProperty:MethodInfo
	Field _targetField:FieldInfo
	Field _isField:Bool
	Field _intProperty:Bool
	
	Field _equation:TweenEquationCall
	
	Field _valueCurrent:Float
	Field _valueCurrentBoxed:Object[]
	Field _valueStart:Float, _valueEnd:Float
	Field _valueDelta:Float
	Field _timeStart:Int, _timeEnd:Int
	Field _timePassed:Int
	Field _duration:Int
	Field _completion:Float
	
	Method _GetValue:Void()
		If _isField
			_valueCurrentBoxed[0] = _targetField.GetValue(_targetObject)
		Else
			_valueCurrentBoxed[0] = _targetGetProperty.Invoke(_targetObject, [])
		EndIf
	End
	
	Method _SetValue:Void()
		If _isField
			_targetField.SetValue(_targetObject, _valueCurrentBoxed[0])
		Else
			_targetSetProperty.Invoke(_targetObject, _valueCurrentBoxed)
		EndIf
	End	
End



Function UpdateSchedules:Void(timePassed:Int = -1)
	If timePassed = -1 Then timePassed = Tick()
	AbuTween.juggler.Update(timePassed)
End